package com.lagou.edu.utils;

import java.io.File;
import java.lang.reflect.Field;
import java.net.URL;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.lagou.edu.factory.BeanFactory;

import lombok.extern.slf4j.Slf4j;

public class ClassUtil {
    public static final Logger log = LoggerFactory.getLogger(ClassUtil.class);
    public static final String FILE_PROTOCOL = "file";

    public static Set<Class<?>> extracPackageClass(String basePackage) {
        //1. 获取classLoader
        ClassLoader classLoader = getClassLoader();

        //2. 获取资源文件的url
        URL url = classLoader.getResource(basePackage.replace(".", "/"));
        if(url == null){
            log.warn("unable to retrieve anything from package:" + basePackage);
            return null;
        }
        //3. 对文件资源类型进行处理
        Set<Class<?>> classSet = new HashSet<>();
        if(url.getProtocol().equalsIgnoreCase(FILE_PROTOCOL)){
            File packageDirectory = new File(url.getPath());
            extractClassFile(classSet, packageDirectory, basePackage);
        }
        return classSet;
    }

    private static void extractClassFile(Set<Class<?>> classSet, File file, String basePackage) {
        if(!file.isDirectory()){
            String absolutePath = file.getAbsolutePath();
            if (absolutePath.endsWith(".class")) {
                //1. 提取包名
                absolutePath = absolutePath.replace(File.separator, ".");
                String className = absolutePath.substring(absolutePath.indexOf(basePackage), absolutePath.lastIndexOf("."));

                //2. 生成对应的class对象并加入classSet中
                Class target = loadClass(className);
                classSet.add(target);
            }
            return;
        }
        Arrays.stream(file.listFiles()).forEach(f -> extractClassFile(classSet, f, basePackage));
    }

    private static Class loadClass(String className) {
        try {
            return Class.forName(className);
        } catch (ClassNotFoundException e) {
            log.error("load class failed!", e);
            throw new RuntimeException(e);
        }
    }

    private static ClassLoader getClassLoader() {
        return Thread.currentThread().getContextClassLoader();
    }

    public static Object newInstance(Class<?> clazz) {
        try {
            return clazz.newInstance();
        } catch (Exception e) {
            log.error("new instance failed!");
            throw new RuntimeException(e);
        }
    }

    public static void setField(Object bean, Field field, Object fieldValue) {

        field.setAccessible(true);
        try {
            field.set(bean, fieldValue);
        } catch (Exception e) {
            log.error("setField error", e);
            throw new RuntimeException(e);
        }
    }
}
